package com.hup.minicontroller.common.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TextView;

import androidx.annotation.Nullable;
import androidx.arch.core.util.Function;

import com.hup.common.R;

import java.util.Arrays;

import lombok.Setter;

/**
 * 包含[文本+值+单位+SeekBar]的自定义SeekBar控件
 */
public class SeekBarView<T> extends LinearLayout implements SeekBar.OnSeekBarChangeListener {
    private static final String TAG = SeekBarView.class.getSimpleName();
    private static final int LAYOUT_ID = R.layout.seek_bar_view;

    //view
    private TextView txtLabel;
    private TextView txtValue;
    private SeekBar sb;
    //xml属性
    private String label;
    private ValueType valueType;
    /**
     * 取值,数据类型:{@link ValueType}
     */
    private Object[] values;
    /**
     * 当前值的index,等于 {@link SeekBar#getProgress()}
     */
    private int valueIndex;
    /**
     * 单位
     */
    private String unit;
    /**
     * SeekBar值监听
     */
    @Setter
    private ValueChangedListener<T> valueChangedListener;

    public SeekBarView(Context context) {
        this(context, null);
    }

    public SeekBarView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SeekBarView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public SeekBarView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(LAYOUT_ID, this);
        txtLabel = findViewById(R.id.label);
        txtValue = findViewById(R.id.value);
        sb = findViewById(R.id.seekBar);
        if (attrs != null) {
            initAttrs(context, attrs);
        }
        sb.setOnSeekBarChangeListener(this);
    }

    private void initAttrs(Context context, AttributeSet attrs) {
        if (attrs == null) return;
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SeekBarView);
        try {
            //label
            label = typedArray.getString(R.styleable.SeekBarView_seek_bar_view_label);
            if (label == null) label = "label:";
            txtLabel.setText(label);
            //数据类型
            int valueTypeInt = typedArray.getInt(R.styleable.SeekBarView_seek_bar_view_value_type, ValueType.INTEGER.value);
            valueType = ValueType.get(valueTypeInt);
            //解析取值数组,并转成对应的数据类型
            String inputValues = typedArray.getString(R.styleable.SeekBarView_seek_bar_view_values);
            if (inputValues == null) inputValues = "0";//为了xml刚添加组件没配置属性时,能正常预览
            String[] split = inputValues.split(",");
            values = new Object[split.length];
            for (int i = values.length - 1; i >= 0; i--) {
                values[i] = valueType.parser.apply(split[i]);
            }
            sb.setMax(values.length - 1);
            //当前值
            valueIndex = typedArray.getInt(R.styleable.SeekBarView_seek_bar_view_value_index, 0);
            if (valueIndex < 0 || valueIndex > values.length - 1) {
                throw new IllegalArgumentException("valueIndex错误:" + valueIndex + ",范围[0," + (values.length - 1) + "]");
            }
            sb.setProgress(valueIndex);
            //单位
            unit = typedArray.getString(R.styleable.SeekBarView_seek_bar_view_unit);
            //更新UI
            fixValueTextWidth(split);
            updateValueText();
        } catch (Exception e) {
            Log.e(TAG, "解析属性异常: ", e);
        } finally {
            typedArray.recycle();
        }
    }

    /**
     * 按[values+unit的最宽字符串]固定txtValue的宽度;
     * 解决SeekBar拖拽时,因为txtValue文本更新导致布局鬼畜的问题
     */
    private void fixValueTextWidth(String[] split) {
        String longest = split[0];
        for (String value : split) {
            if (value.length() > longest.length()) longest = value;
        }
        if (unit != null) longest += unit;
        float width = txtValue.getPaint().measureText(longest);
//        Log.i(TAG, "fixValueTextWidth: " + width + ", str=" + longest);
        ViewGroup.LayoutParams params = txtValue.getLayoutParams();
        params.width = (int) width + 1;
        txtValue.setLayoutParams(params);
    }

    /**
     * 更新[txtValue]的文本
     */
    private void updateValueText() {
        if (unit == null) {
            txtValue.setText(values[valueIndex].toString());
        } else {
            txtValue.setText(String.format("%s%s", values[valueIndex], unit));
        }
    }

    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        Log.d(TAG, "onProgressChanged: label=" + label + ", progress=" + progress + ", fromUser=" + fromUser);
        /*
        非常坑!!!!
        屏幕旋转后,Activity重新onCreate时更新progress(正常更新后),
            结果后面会有一个错误progress值的事件会触发到此处!!!
            new Throwable().printStackTrace();显示是Activity.onRestoreInstanceState的锅
            需要重写Activity.onRestoreInstanceState,屏蔽super
         */
        //new Throwable().printStackTrace();
        valueIndex = progress;
        updateValueText();
        if (valueChangedListener != null) valueChangedListener.onValueChanged(getValue(), fromUser);
    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
    }

    @SuppressWarnings("unchecked")
    public T getValue() {
        return (T) values[valueIndex];
    }

    public void setValue(T value) {
        Log.d(TAG, "setValue: " + value + ", label=" + label);
        for (int i = 0, valuesLength = values.length; i < valuesLength; i++) {
            Object o = values[i];
            if (values[i].equals(value)) {
                sb.setProgress(i);//由SB监听触发更新UI和valueIndex
                return;
            }
        }
        Log.e(TAG, "setValue: value异常:" + value + ", values=" + Arrays.toString(values));
    }

    public void setValues(String valuesStr) {
        if (valuesStr == null) {
            Log.e(TAG, "setValues: 入参不能为null");
            return;
        }
        String[] split = valuesStr.split(",");
        values = new Object[split.length];
        for (int i = values.length - 1; i >= 0; i--) {
            values[i] = valueType.parser.apply(split[i]);
        }
        sb.setMax(values.length - 1);
        valueIndex = Math.min(valueIndex, values.length - 1);

        fixValueTextWidth(split);
        updateValueText();
    }

    /**
     * 数据类型
     */
    private enum ValueType {
        INTEGER(0, Integer::parseInt),
        FLOAT(1, Float::parseFloat),
        DOUBLE(2, Double::parseDouble),
        STRING(3, s -> s);

        private final int value;
        private final Function<String, Object> parser;

        ValueType(int value, Function<String, Object> parser) {
            this.value = value;
            this.parser = parser;
        }

        private static ValueType get(int value) {
            for (ValueType type : values()) {
                if (type.value == value) return type;
            }
            throw new IllegalArgumentException("取值异常:" + value);
        }
    }

    public interface ValueChangedListener<T> {
        void onValueChanged(T value, boolean fromUser);
    }

}
